package dse.messages.singleversion;

import java.util.HashMap;
import java.util.TreeSet;

import dse.*;
import dse.messages.Message;
import dse.messages.MessageHandler;
import dse.messages.MessagePurpose;
import dse.messages.MessageSender;
import dse.messages.MessageType;
import dse.messages.Transaction;
import dse.messages.multiversion.VersionReader;

public class SendMACMessageHandler extends MessageSender implements
		MessageHandler {
	private DataObject dobj;
	private Version version;
	private ShareDownloader downloader;
	
	public SendMACMessageHandler(Experiment exp, DataObject dobj, Version version, 
			ShareDownloader downloader){
		super(exp);
		
		this.dobj = dobj;
		this.version = version;
		this.downloader = downloader;
	}
	@Override
	public boolean acceptMessage(Message message) {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public void messageInterupted(ExperimentRecorder recorder, Message message,
			double time) {
		// TODO Auto-generated method stub
		if(ExperimentRecorder.debug)
			recorder.debug(this, "msgIntrpt: " + message, time);
		Node sender = message.from();
		DataShare share = sender.getDataShare(dobj);
		if(share != null){
			share.addVolatileVersion(version, message.to());
			commit(share, sender, recorder, time);
		}
	}

	@Override
	public void messageReceived(ExperimentRecorder recorder, Message message,
			double time) {
		// TODO Auto-generated method stub
		if (message.messageType() != MessageType.SendMAC) {
			recorder.warn(
					"SendMACMessageHandler recieved " + message.messageType() + " message."
					);
			return;
		}
		
		Node receiver = message.to();
		DataShare share = receiver.getDataShare(dobj);
		if (share != null)
		{
			share.addVolatileVersion(version, message.from());
			commit(share, receiver, recorder, time);
		}
		else
		{
			this.messageInterupted(recorder, message, time);
		}
	}
	
	private void commit(DataShare share, Node n, ExperimentRecorder recorder, double time){
		if(share.getVolatileVersions().get(version).size() >= dobj.shareCount()){
			Version ver = version;
			if(version.compareTo(share.getLatest()) > 0){
				ver = share.getLatest();
				share.updateVersion(version);
				share.removeVolatileVersion(version);
			}
			else{
				share.removeVolatileVersion(version);
			}
			
			HashMap<Transaction, TreeSet<Version>> ir = share.getIncompleteRead();
			if(ir != null){
				for(Transaction id : ir.keySet()){
					if(!ir.get(id).contains(ver) && (ver.compareTo(ir.get(id).first()) >0)){
						Message m = super.createShareDownloadMessage(n, id.primaryNode(), 
								dobj, version, MessagePurpose.DataObjectRequest, (VersionReader)id);
						if(ExperimentRecorder.debug)
							recorder.debug(this, "new msg: " + m, time);
						experiment.messageQueue().enqueueMessage(m, time);
					}
				}	
			}
			
			downloader.shareUpdated(recorder, n, dobj, share.getIndex(), time);
		}
	}	
}
